/**
* Copyright @ 2023 iAuto (Shanghai) Co., Ltd.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are NOT permitted except as agreed by
* iAuto (Shanghai) Co., Ltd.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
//
/*eslint-disable*/
import Blockly from '@scene/scene-blocks';

const ELEMENT_TYPE = {
    input_value: 'input_value',
    input_statement: 'input_statement',
    input_dummy: 'input_dummy',
    alt: 'alt',
    type: 'type',
    align: 'align',
    check: 'check',
    name: 'name',
    paramName: 'paramName',
};

Blockly.FieldNumber.prototype.setConstraints_ = function (opt_min, opt_max, opt_precision) {
    this.decimalAllowed_ = (typeof opt_precision == 'undefined') ||
        isNaN(opt_precision) || (opt_precision == 0) ||
        (Math.floor(opt_precision) != opt_precision);
    this.negativeAllowed_ = (typeof opt_min == 'undefined') || isNaN(opt_min) ||
        opt_min < 0;
    this.exponentialAllowed_ = this.decimalAllowed_;

    // 添加最小值和最大值的限制
    if (typeof opt_min != 'undefined' && !isNaN(opt_min)) {
        this.minLimit_ = opt_min;
    }
    if (typeof opt_max != 'undefined' && !isNaN(opt_max)) {
        this.maxLimit_ = opt_max;
    }
};

// 初始化积木
// 加载针对值的取值范围进行限制
Blockly.jsonInitFactory_ = function (jsonDef) {
    return function () {
        this.jsonInit(jsonDef);

        if (jsonDef.limit) {
            const numField = this.getField("NUM");

            // 设置校验函数
            numField.setValidator(function (newValue) {
                // 解析新值为浮点数
                let value = newValue

                // 设置最小值和最大值
                const min = numField.minLimit_; // 使用 minLimit_ 属性作为最小值
                const max = numField.maxLimit_; // 使用 maxLimit_ 属性作为最大值

                // 检测值内容是不是 NaN
                if (isNaN(Number(value))) {
                    // 正则移除非数字内容
                    value = value.replace(/\D/g, "");
                }
                // 根据最小值和最大值限制值的范围
                if (!isNaN(max) && !isNaN(min)) {
                    value = Math.min(Math.max(value, min), max);
                } else if (!isNaN(max)) {
                    value = Math.min(value, max);
                } else if (!isNaN(min)) {
                    value = Math.max(value, min);
                } 

                // 返回修正后的值
                return String(value);
            });
        }
    };
};

Blockly.Field.prototype.paramName = null;

Blockly.Field.prototype.setParamName = function(name) {
    this.paramName = name;
};

Blockly.Gesture.prototype.doFieldClick_ = function () {
    this.startField_.showEditor_();
    this.bringBlockToFront_();
    var event = new Blockly.Events.Ui(null, 'field', null, null);
    event.block = this.startField_
    event.targetBlock_ = this.targetBlock_
    event.workspaceId = this.startWorkspace_.id;
    Blockly.Events.fire(event);
};

function startsWith(string, prefix) {
    return string.indexOf(prefix) === 0;
}

Blockly.Block.prototype.interpolate_ = function (message, args, lastDummyAlign) {
    let tokens = Blockly.utils.tokenizeInterpolation(message);
    // Interpolate the arguments. Build a list of elements.
    let indexDup = [];
    let indexCount = 0;
    let elements = [];
    for (let i = 0; i < tokens.length; i++) {
        let token = tokens[i];
        if (typeof token == 'number') {
            if (token > args.length || token <= 0) {
                throw new Error('Block "' + this.type + '": ' +
                    'Messages index %' + token + ' out of range.');
            }
            if (indexDup[token]) {
                throw new Error('Block "' + this.type + '": ' +
                    'Messages index %' + token + ' duplicated.');
            }
            indexDup[token] = true;
            indexCount++;
            elements.push(args[token - 1]);
        } else {
            token = token.trim();
            if (token) {
                elements.push(token);
            }
        }
    }
    if (indexCount != args.length) {
        throw new Error('Block "' + this.type + '": ' +
            'Messages does not reference all ' + args.length + ' arg(s).');
    }
    // Add last dummy input if needed.
    if (elements.length && (typeof elements[elements.length - 1] == 'string' ||
        startsWith(
            elements[elements.length - 1][ELEMENT_TYPE.type], 'field_'))) {
        let dummyInput = { type: ELEMENT_TYPE.input_dummy };
        if (lastDummyAlign) {
            dummyInput[ELEMENT_TYPE.align] = lastDummyAlign;
        }
        elements.push(dummyInput);
    }
    // Lookup of alignment constants.
    let alignmentLookup = {
        'LEFT': Blockly.ALIGN_LEFT,
        'RIGHT': Blockly.ALIGN_RIGHT,
        'CENTRE': Blockly.ALIGN_CENTRE
    };
    // Populate block with inputs and fields.
    let fieldStack = [];
    for (let i = 0; i < elements.length; i++) {
        let element = elements[i];
        if (typeof element == 'string') {
            fieldStack.push([element, undefined]);
        } else {
            let field = null;
            let input = null;
            do {
                var altRepeat = false;
                if (typeof element == 'string') {
                    field = new Blockly.FieldLabel(element);
                } else {
                    switch (element[ELEMENT_TYPE.type]) {
                        case ELEMENT_TYPE.input_value:
                            input = this.appendValueInput(element[ELEMENT_TYPE.name]);
                            break;
                        case ELEMENT_TYPE.input_statement:
                            input = this.appendStatementInput(element[ELEMENT_TYPE.name]);
                            break;
                        case ELEMENT_TYPE.input_dummy:
                            input = this.appendDummyInput(element[ELEMENT_TYPE.name]);
                            break;
                        default:
                            field = Blockly.Field.fromJson(element);
                            // 参数对象设置一个 paramName 属性
                            field.setParamName(element[ELEMENT_TYPE.paramName]);

                            // Unknown field.
                            if (!field) {
                                if (element[ELEMENT_TYPE.alt]) {
                                    element = element[ELEMENT_TYPE.alt];
                                    altRepeat = true;
                                } else {
                                    console.warn('Blockly could not create a field of type ' +
                                        element[ELEMENT_TYPE.type] +
                                        '. You may need to register your custom field.  See ' +
                                        'github.com/google/blockly/issues/1584');
                                }
                            }
                    }
                }
            } while (altRepeat);
            if (field) {
                fieldStack.push([field, element[ELEMENT_TYPE.name]]);
            } else if (input) {
                if (element[ELEMENT_TYPE.check]) {
                    input.setCheck(element[ELEMENT_TYPE.check]);
                }
                if (element[ELEMENT_TYPE.align]) {
                    input.setAlign(alignmentLookup[element[ELEMENT_TYPE.align]]);
                }
                for (let j = 0; j < fieldStack.length; j++) {
                    input.appendField(fieldStack[j][0], fieldStack[j][1]);
                }
                fieldStack.length = 0;
            }
        }
    }
};


/**
 * LeftTop the workspace.
 */
 Blockly.WorkspaceSvg.prototype.scrollToLeftTop = function (xOffset = 0, yOffset = 0) {
    if (!this.scrollbar) {
      // Can't center a non-scrolling workspace.
      console.warn('Tried to scroll a non-scrollable workspace.');
      return;
    }
    // Hide the WidgetDiv without animation (zoom makes field out of place with div)
    Blockly.WidgetDiv.hide(true);
    Blockly.DropDownDiv.hideWithoutAnimation();
    Blockly.hideChaff(false);
    var metrics = this.getMetrics();
    const x = -metrics.contentLeft - xOffset;
    const y = -metrics.contentTop - yOffset;
    this.scrollbar.set(x, y);
  };